home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / gnustuff / tos / g__~1 / gplibs15.zoo / sbufvsca.cc < prev    next >
Encoding:
C/C++ Source or Header  |  1992-10-01  |  17.3 KB  |  760 lines

  1. /*
  2.  * Copyright (c) 1990 The Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms are permitted
  6.  * provided that the above copyright notice and this paragraph are
  7.  * duplicated in all such forms and that any documentation,
  8.  * advertising materials, and other materials related to such
  9.  * distribution and use acknowledge that the software was developed
  10.  * by the University of California, Berkeley.  The name of the
  11.  * University may not be used to endorse or promote products derived
  12.  * from this software without specific prior written permission.
  13.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  14.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  15.  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  16.  */
  17.  
  18. // Extensively hacked for GNU iostream by Per Bothner 1991, 1992.
  19. // Changes copyright Per Bothner 1992.
  20.  
  21. #if defined(LIBC_SCCS) && !defined(lint)
  22. static char sccsid[] = "%W% (Berkeley) %G%";
  23. #endif /* LIBC_SCCS and not lint */
  24.  
  25. #include <ioprivat.h>
  26. #include <ctype.h>
  27. #ifndef NO_STDARG
  28. #include <stdarg.h>
  29. #else
  30. #include <varargs.h>
  31. #endif
  32.  
  33. #ifdef sun /* SunOS incorrectly defines size_t to be int. */
  34. #define hardway
  35. #endif
  36.  
  37. #ifndef    NO_FLOATING_POINT
  38. #define FLOATING_POINT
  39. #endif
  40.  
  41. #ifdef FLOATING_POINT
  42. #include <floatio.h>
  43. #define    BUF    (MAXEXP+MAXFRACT+3)    /* 3 = sign + decimal point + NUL */
  44. #else
  45. #define    BUF    40
  46. #endif
  47.  
  48. /*
  49.  * Flags used during conversion.
  50.  */
  51. #define    LONG        0x01    /* l: long or double */
  52. #define    LONGDBL        0x02    /* L: long double; unimplemented */
  53. #define    SHORT        0x04    /* h: short */
  54. #define    SUPPRESS    0x08    /* suppress assignment */
  55. #define    POINTER        0x10    /* weird %p pointer (`fake hex') */
  56. #define    NOSKIP        0x20    /* do not skip blanks */
  57.  
  58. /*
  59.  * The following are used in numeric conversions only:
  60.  * SIGNOK, NDIGITS, DPTOK, and EXPOK are for floating point;
  61.  * SIGNOK, NDIGITS, PFXOK, and NZDIGITS are for integral.
  62.  */
  63. #define    SIGNOK        0x40    /* +/- is (still) legal */
  64. #define    NDIGITS        0x80    /* no digits detected */
  65.  
  66. #define    DPTOK        0x100    /* (float) decimal point is still legal */
  67. #define    EXPOK        0x200    /* (float) exponent (e+3, etc) still legal */
  68.  
  69. #define    PFXOK        0x100    /* 0x prefix is (still) legal */
  70. #define    NZDIGITS    0x200    /* no zero digits detected */
  71.  
  72. /*
  73.  * Conversion types.
  74.  */
  75. #define    CT_CHAR        0    /* %c conversion */
  76. #define    CT_CCL        1    /* %[...] conversion */
  77. #define    CT_STRING    2    /* %s conversion */
  78. #define    CT_INT        3    /* integer, i.e., strtol or strtoul */
  79. #define    CT_FLOAT    4    /* floating, i.e., strtod */
  80.  
  81. #define u_char unsigned char
  82. #define u_long unsigned long
  83.  
  84. extern "C" u_long strtoul(const char*, char**, int);
  85. static const u_char *__sccl(register char *tab, register const u_char *fmt);
  86.  
  87. // If state is non-NULL, set failbit and/or eofbit as appropriate.
  88.  
  89. int streambuf::vscan(char const *fmt0,
  90.              _G_va_list ap,
  91.              ios::iostate *state /* = NULL */)
  92. {
  93.     register const u_char *fmt = (const u_char *)fmt0;
  94.     register int c;        /* character from format, or conversion */
  95.     register size_t width;    /* field width, or 0 */
  96.     register char *p;    /* points into all kinds of strings */
  97.     register int n;        /* handy integer */
  98.     register int flags;    /* flags as defined above */
  99.     register char *p0;    /* saves original value of p when necessary */
  100.     int nassigned;        /* number of fields assigned */
  101.     int nread;        /* number of characters consumed from fp */
  102.     // Assignments to base and ccfn are just to suppress warnings from gcc.
  103.     int base = 0;        /* base argument to strtol/strtoul */
  104.     u_long (*ccfn)(const char*, char**, int) = 0;
  105.     // conversion function (strtol/strtoul)
  106.     char ccltab[256];    /* character class table for %[...] */
  107.     char buf[BUF];        /* buffer for numeric conversions */
  108.     int seen_eof = 0;
  109.  
  110.     /* `basefix' is used to avoid `if' tests in the integer scanner */
  111.     static short basefix[17] =
  112.         { 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
  113.  
  114.     nassigned = 0;
  115.     nread = 0;
  116.     for (;;) {
  117.         c = *fmt++;
  118.         if (c == 0)
  119.             goto done;
  120.         if (isspace(c)) {
  121.             for (;;) {
  122.                     c = sbumpc();
  123.                 if (c == EOF)
  124.                     goto eof_failure;
  125.                 if (!isspace(c)) {
  126.                     sputbackc(c);
  127.                     break;
  128.                 }
  129.                 nread++;
  130.             }
  131.             continue;
  132.         }
  133.         if (c != '%')
  134.             goto literal;
  135.         width = 0;
  136.         flags = 0;
  137.         /*
  138.          * switch on the format.  continue if done;
  139.          * break once format type is derived.
  140.          */
  141. again:        c = *fmt++;
  142.         switch (c) {
  143.         case '%':
  144. literal:
  145.                 n = sbumpc();
  146.             if (n == EOF)
  147.                 goto eof_failure;
  148.             if (n != c) {
  149.                 sputbackc(n);
  150.                 goto match_failure;
  151.             }
  152.             nread++;
  153.             continue;
  154.  
  155.         case '*':
  156.             flags |= SUPPRESS;
  157.             goto again;
  158.         case 'l':
  159.             flags |= LONG;
  160.             goto again;
  161.         case 'L':
  162.             flags |= LONGDBL;
  163.             goto again;
  164.         case 'h':
  165.             flags |= SHORT;
  166.             goto again;
  167.  
  168.         case '0': case '1': case '2': case '3': case '4':
  169.         case '5': case '6': case '7': case '8': case '9':
  170.             width = width * 10 + c - '0';
  171.             goto again;
  172.  
  173.         /*
  174.          * Conversions.
  175.          * Those marked `compat' are for 4.[123]BSD compatibility.
  176.          *
  177.          * (According to ANSI, E and X formats are supposed
  178.          * to the same as e and x.  Sorry about that.)
  179.          */
  180.         case 'D':    /* compat */
  181.             flags |= LONG;
  182.             /* FALLTHROUGH */
  183.         case 'd':
  184.             c = CT_INT;
  185.             ccfn = (u_long (*)(const char, char**, int))strtol;
  186.             base = 10;
  187.             break;
  188.  
  189.         case 'i':
  190.             c = CT_INT;
  191.             ccfn = (u_long (*)(const char, char**, int))strtol;
  192.             base = 0;
  193.             break;
  194.  
  195.         case 'O':    /* compat */
  196.             flags |= LONG;
  197.             /* FALLTHROUGH */
  198.         case 'o':
  199.             c = CT_INT;
  200.             ccfn = strtoul;
  201.             base = 8;
  202.             break;
  203.  
  204.         case 'u':
  205.             c = CT_INT;
  206.             ccfn = strtoul;
  207.             base = 10;
  208.             break;
  209.  
  210.         case 'X':    /* compat   XXX */
  211.             flags |= LONG;
  212.             /* FALLTHROUGH */
  213.         case 'x':
  214.             flags |= PFXOK;    /* enable 0x prefixing */
  215.             c = CT_INT;
  216.             ccfn = strtoul;
  217.             base = 16;
  218.             break;
  219.  
  220. #ifdef FLOATING_POINT
  221.         case 'E':    /* compat   XXX */
  222.         case 'F':    /* compat */
  223.             flags |= LONG;
  224.             /* FALLTHROUGH */
  225.         case 'e': case 'f': case 'g':
  226.             c = CT_FLOAT;
  227.             break;
  228. #endif
  229.  
  230.         case 's':
  231.             c = CT_STRING;
  232.             break;
  233.  
  234.         case '[':
  235.             fmt = __sccl(ccltab, fmt);
  236.             flags |= NOSKIP;
  237.             c = CT_CCL;
  238.             break;
  239.  
  240.         case 'c':
  241.             flags |= NOSKIP;
  242.             c = CT_CHAR;
  243.             break;
  244.  
  245.         case 'p':    /* pointer format is like hex */
  246.             flags |= POINTER | PFXOK;
  247.             c = CT_INT;
  248.             ccfn = strtoul;
  249.             base = 16;
  250.             break;
  251.  
  252.         case 'n':
  253.             if (flags & SUPPRESS)    /* ??? */
  254.                 continue;
  255.             if (flags & SHORT)
  256.                 *va_arg(ap, short *) = nread;
  257.             else if (flags & LONG)
  258.                 *va_arg(ap, long *) = nread;
  259.             else
  260.                 *va_arg(ap, int *) = nread;
  261.             continue;
  262.  
  263.         /*
  264.          * Disgusting backwards compatibility hacks.    XXX
  265.          */
  266.         case '\0':    /* compat */
  267.                 nassigned = EOF;
  268.             goto done;
  269.  
  270.         default:    /* compat */
  271.             if (isupper(c))
  272.                 flags |= LONG;
  273.             c = CT_INT;
  274.             ccfn = (u_long (*)(const char, char**, int))strtol;
  275.             base = 10;
  276.             break;
  277.         }
  278.  
  279.         /*
  280.          * We have a conversion that requires input.
  281.          */
  282.         if (sgetc() == EOF)
  283.             goto eof_failure;
  284.  
  285.         /*
  286.          * Consume leading white space, except for formats
  287.          * that suppress this.
  288.          */
  289.         if ((flags & NOSKIP) == 0) {
  290.             n = *_gptr;
  291.             while (isspace(n)) {
  292.             _gptr++;
  293.             nread++;
  294.             n = sgetc();
  295.             if (n == EOF)
  296.                 goto eof_failure;
  297.             }
  298.             // Note that there is at least one character in
  299.             // the buffer, so conversions that do not set NOSKIP
  300.             // can no longer result in an input failure.
  301.         }
  302.  
  303.         /*
  304.          * Do the conversion.
  305.          */
  306.         switch (c) {
  307.  
  308.         case CT_CHAR:
  309.             /* scan arbitrary characters (sets NOSKIP) */
  310.             if (width == 0) // FIXME!
  311.                 width = 1;
  312.             if (flags & SUPPRESS) {
  313.                 size_t sum = 0;
  314.                 for (;;) {
  315.                 if ((n = _egptr - _gptr) < (int)width) {
  316.                     sum += n;
  317.                     width -= n;
  318.                     _gptr += n;
  319.                     if (underflow() == EOF)
  320.                     if (sum == 0)
  321.                         goto eof_failure;
  322.                     else {
  323.                         seen_eof++;
  324.                         break;
  325.                     }
  326.                 } else {
  327.                     sum += width;
  328.                     _gptr += width;
  329.                     break;
  330.                 }
  331.                 }
  332.                 nread += sum;
  333.             } else {
  334.                 size_t r = sgetn((char*)va_arg(ap, char*),
  335.                          width);
  336.                 if (r != width)
  337.                 goto eof_failure;
  338.                 nread += r;
  339.                 nassigned++;
  340.             }
  341.             break;
  342.  
  343.         case CT_CCL:
  344.             /* scan a (nonempty) character class (sets NOSKIP) */
  345.             if (width == 0)
  346.                 width = ~0;    /* `infinity' */
  347.             /* take only those things in the class */
  348.             if (flags & SUPPRESS) {
  349.                 n = 0;
  350.                 while (ccltab[*_gptr]) {
  351.                     n++, _gptr++;
  352.                     if (--width == 0)
  353.                     break;
  354.                     if (sgetc() == EOF) {
  355.                     if (n == 0)
  356.                         goto eof_failure;
  357.                     seen_eof++;
  358.                     break;
  359.                     }
  360.                 }
  361.                 if (n == 0)
  362.                     goto match_failure;
  363.             } else {
  364.                 p0 = p = va_arg(ap, char *);
  365.                 while (ccltab[*_gptr]) {
  366.                 *p++ = *_gptr++;
  367.                 if (--width == 0)
  368.                     break;
  369.                 if (sgetc() == EOF) {
  370.                     if (p == p0)
  371.                     goto eof_failure;
  372.                     seen_eof++;
  373.                     break;
  374.                 }
  375.                 }
  376.                 n = p - p0;
  377.                 if (n == 0)
  378.                 goto match_failure;
  379.                 *p = 0;
  380.                 nassigned++;
  381.             }
  382.             nread += n;
  383.             break;
  384.  
  385.         case CT_STRING:
  386.             /* like CCL, but zero-length string OK, & no NOSKIP */
  387.             if (width == 0)
  388.                 width = ~0;
  389.             if (flags & SUPPRESS) {
  390.                 n = 0;
  391.                 while (!isspace(*_gptr)) {
  392.                     n++, _gptr++;
  393.                     if (--width == 0)
  394.                         break;
  395.                     if (sgetc() == EOF) {
  396.                         seen_eof++;
  397.                         break;
  398.                     }
  399.                 }
  400.                 nread += n;
  401.             } else {
  402.                 p0 = p = va_arg(ap, char *);
  403.                 while (!isspace(*_gptr)) {
  404.                     *p++ = *_gptr++;
  405.                     if (--width == 0)
  406.                         break;
  407.                     if (sgetc() == EOF) {
  408.                         seen_eof++;
  409.                         break;
  410.                     }
  411.                 }
  412.                 *p = 0;
  413.                 nread += p - p0;
  414.                 nassigned++;
  415.             }
  416.             continue;
  417.  
  418.         case CT_INT:
  419.             /* scan an integer as if by strtol/strtoul */
  420. #ifdef hardway
  421.             if (width == 0 || width > sizeof(buf) - 1)
  422.                 width = sizeof(buf) - 1;
  423. #else
  424.             /* size_t is unsigned, hence this optimisation */
  425.             if (--width > sizeof(buf) - 2)
  426.                 width = sizeof(buf) - 2;
  427.             width++;
  428. #endif
  429.             flags |= SIGNOK | NDIGITS | NZDIGITS;
  430.             for (p = buf; width; width--) {
  431.                 c = *_gptr;
  432.                 /*
  433.                  * Switch on the character; `goto ok'
  434.                  * if we accept it as a part of number.
  435.                  */
  436.                 switch (c) {
  437.  
  438.                 /*
  439.                  * The digit 0 is always legal, but is
  440.                  * special.  For %i conversions, if no
  441.                  * digits (zero or nonzero) have been
  442.                  * scanned (only signs), we will have
  443.                  * base==0.  In that case, we should set
  444.                  * it to 8 and enable 0x prefixing.
  445.                  * Also, if we have not scanned zero digits
  446.                  * before this, do not turn off prefixing
  447.                  * (someone else will turn it off if we
  448.                  * have scanned any nonzero digits).
  449.                  */
  450.                 case '0':
  451.                     if (base == 0) {
  452.                         base = 8;
  453.                         flags |= PFXOK;
  454.                     }
  455.                     if (flags & NZDIGITS)
  456.                         flags &= ~(SIGNOK|NZDIGITS|NDIGITS);
  457.                     else
  458.                         flags &= ~(SIGNOK|PFXOK|NDIGITS);
  459.                     goto ok;
  460.  
  461.                 /* 1 through 7 always legal */
  462.                 case '1': case '2': case '3':
  463.                 case '4': case '5': case '6': case '7':
  464.                     base = basefix[base];
  465.                     flags &= ~(SIGNOK | PFXOK | NDIGITS);
  466.                     goto ok;
  467.  
  468.                 /* digits 8 and 9 ok iff decimal or hex */
  469.                 case '8': case '9':
  470.                     base = basefix[base];
  471.                     if (base <= 8)
  472.                         break;    /* not legal here */
  473.                     flags &= ~(SIGNOK | PFXOK | NDIGITS);
  474.                     goto ok;
  475.  
  476.                 /* letters ok iff hex */
  477.                 case 'A': case 'B': case 'C':
  478.                 case 'D': case 'E': case 'F':
  479.                 case 'a': case 'b': case 'c':
  480.                 case 'd': case 'e': case 'f':
  481.                     /* no need to fix base here */
  482.                     if (base <= 10)
  483.                         break;    /* not legal here */
  484.                     flags &= ~(SIGNOK | PFXOK | NDIGITS);
  485.                     goto ok;
  486.  
  487.                 /* sign ok only as first character */
  488.                 case '+': case '-':
  489.                     if (flags & SIGNOK) {
  490.                         flags &= ~SIGNOK;
  491.                         goto ok;
  492.                     }
  493.                     break;
  494.  
  495.                 /* x ok iff flag still set & 2nd char */
  496.                 case 'x': case 'X':
  497.                     if (flags & PFXOK && p == buf + 1) {
  498.                         base = 16;    /* if %i */
  499.                         flags &= ~PFXOK;
  500.                         goto ok;
  501.                     }
  502.                     break;
  503.                 }
  504.  
  505.                 /*
  506.                  * If we got here, c is not a legal character
  507.                  * for a number.  Stop accumulating digits.
  508.                  */
  509.                 break;
  510.         ok:
  511.                 /*
  512.                  * c is legal: store it and look at the next.
  513.                  */
  514.                 *p++ = c;
  515.                 _gptr++;
  516.                 if (sgetc() == EOF) {
  517.                     seen_eof++;
  518.                     break;        /* EOF */
  519.                 }
  520.                 }
  521.             /*
  522.              * If we had only a sign, it is no good; push
  523.              * back the sign.  If the number ends in `x',
  524.              * it was [sign] '0' 'x', so push back the x
  525.              * and treat it as [sign] '0'.
  526.              */
  527.             if (flags & NDIGITS) {
  528.                 if (p > buf)
  529.                     (void) sputbackc(*(u_char *)--p);
  530.                 goto match_failure;
  531.             }
  532.             c = ((u_char *)p)[-1];
  533.             if (c == 'x' || c == 'X') {
  534.                 --p;
  535.                 (void) sputbackc(c);
  536.             }
  537.             if ((flags & SUPPRESS) == 0) {
  538.                 u_long res;
  539.  
  540.                 *p = 0;
  541.                 res = (*ccfn)(buf, (char **)NULL, base);
  542.                 if (flags & POINTER)
  543.                     *va_arg(ap, void **) = (void *)res;
  544.                 else if (flags & SHORT)
  545.                     *va_arg(ap, short *) = res;
  546.                 else if (flags & LONG)
  547.                     *va_arg(ap, long *) = res;
  548.                 else
  549.                     *va_arg(ap, int *) = res;
  550.                 nassigned++;
  551.             }
  552.             nread += p - buf;
  553.             break;
  554.  
  555. #ifdef FLOATING_POINT
  556.         case CT_FLOAT:
  557.             /* scan a floating point number as if by strtod */
  558. #ifdef hardway
  559.             if (width == 0 || width > sizeof(buf) - 1)
  560.                 width = sizeof(buf) - 1;
  561. #else
  562.             /* size_t is unsigned, hence this optimisation */
  563.             if (--width > sizeof(buf) - 2)
  564.                 width = sizeof(buf) - 2;
  565.             width++;
  566. #endif
  567.             flags |= SIGNOK | NDIGITS | DPTOK | EXPOK;
  568.             for (p = buf; width; width--) {
  569.                 c = *_gptr;
  570.                 /*
  571.                  * This code mimicks the integer conversion
  572.                  * code, but is much simpler.
  573.                  */
  574.                 switch (c) {
  575.  
  576.                 case '0': case '1': case '2': case '3':
  577.                 case '4': case '5': case '6': case '7':
  578.                 case '8': case '9':
  579.                     flags &= ~(SIGNOK | NDIGITS);
  580.                     goto fok;
  581.  
  582.                 case '+': case '-':
  583.                     if (flags & SIGNOK) {
  584.                         flags &= ~SIGNOK;
  585.                         goto fok;
  586.                     }
  587.                     break;
  588.                 case '.':
  589.                     if (flags & DPTOK) {
  590.                         flags &= ~(SIGNOK | DPTOK);
  591.                         goto fok;
  592.                     }
  593.                     break;
  594.                 case 'e': case 'E':
  595.                     /* no exponent without some digits */
  596.                     if ((flags&(NDIGITS|EXPOK)) == EXPOK) {
  597.                         flags =
  598.                             (flags & ~(EXPOK|DPTOK)) |
  599.                             SIGNOK | NDIGITS;
  600.                         goto fok;
  601.                     }
  602.                     break;
  603.                 }
  604.                 break;
  605.         fok:
  606.                 *p++ = c;
  607.                 _gptr++;
  608.                 if (sgetc() == EOF) {
  609.                     seen_eof++;
  610.                     break;    /* EOF */
  611.                 }
  612.             }
  613.             /*
  614.              * If no digits, might be missing exponent digits
  615.              * (just give back the exponent) or might be missing
  616.              * regular digits, but had sign and/or decimal point.
  617.              */
  618.             if (flags & NDIGITS) {
  619.                 if (flags & EXPOK) {
  620.                     /* no digits at all */
  621.                     while (p > buf)
  622.                         sputbackc(*(u_char *)--p);
  623.                     goto match_failure;
  624.                 }
  625.                 /* just a bad exponent (e and maybe sign) */
  626.                 c = *(u_char *)--p;
  627.                 if (c != 'e' && c != 'E') {
  628.                     (void)sputbackc(c);/* sign */
  629.                     c = *(u_char *)--p;
  630.                 }
  631.                 (void) sputbackc(c);
  632.             }
  633.             if ((flags & SUPPRESS) == 0) {
  634.                 double res;
  635.                 *p = 0;
  636. #ifdef USE_DTOA
  637.                 res = strtod(buf, NULL);
  638. #else
  639.                 res = atof(buf);
  640. #endif
  641.                 if (flags & LONG)
  642.                     *va_arg(ap, double *) = res;
  643.                 else
  644.                     *va_arg(ap, float *) = res;
  645.                 nassigned++;
  646.             }
  647.             nread += p - buf;
  648.             break;
  649. #endif /* FLOATING_POINT */
  650.         }
  651.     }
  652. eof_failure:
  653.     seen_eof++;
  654. input_failure:
  655.     if (nassigned == 0)
  656.         nassigned = -1;
  657. match_failure:
  658.     if (state)
  659.         *state |= ios::failbit;
  660. done:
  661.     if (state && seen_eof)
  662.         *state |= ios::eofbit;
  663.     return (nassigned);
  664. }
  665.  
  666. /*
  667.  * Fill in the given table from the scanset at the given format
  668.  * (just after `[').  Return a pointer to the character past the
  669.  * closing `]'.  The table has a 1 wherever characters should be
  670.  * considered part of the scanset.
  671.  */
  672. static const u_char *__sccl(register char *tab, register const u_char *fmt)
  673. {
  674.     register int c, n, v;
  675.  
  676.     /* first `clear' the whole table */
  677.     c = *fmt++;        /* first char hat => negated scanset */
  678.     if (c == '^') {
  679.         v = 1;        /* default => accept */
  680.         c = *fmt++;    /* get new first char */
  681.     } else
  682.         v = 0;        /* default => reject */
  683.     /* should probably use memset here */
  684.     for (n = 0; n < 256; n++)
  685.         tab[n] = v;
  686.     if (c == 0)
  687.         return (fmt - 1);/* format ended before closing ] */
  688.  
  689.     /*
  690.      * Now set the entries corresponding to the actual scanset
  691.      * to the opposite of the above.
  692.      *
  693.      * The first character may be ']' (or '-') without being special;
  694.      * the last character may be '-'.
  695.      */
  696.     v = 1 - v;
  697.     for (;;) {
  698.         tab[c] = v;        /* take character c */
  699. doswitch:
  700.         n = *fmt++;        /* and examine the next */
  701.         switch (n) {
  702.  
  703.         case 0:            /* format ended too soon */
  704.             return (fmt - 1);
  705.  
  706.         case '-':
  707.             /*
  708.              * A scanset of the form
  709.              *    [01+-]
  710.              * is defined as `the digit 0, the digit 1,
  711.              * the character +, the character -', but
  712.              * the effect of a scanset such as
  713.              *    [a-zA-Z0-9]
  714.              * is implementation defined.  The V7 Unix
  715.              * scanf treats `a-z' as `the letters a through
  716.              * z', but treats `a-a' as `the letter a, the
  717.              * character -, and the letter a'.
  718.              *
  719.              * For compatibility, the `-' is not considerd
  720.              * to define a range if the character following
  721.              * it is either a close bracket (required by ANSI)
  722.              * or is not numerically greater than the character
  723.              * we just stored in the table (c).
  724.              */
  725.             n = *fmt;
  726.             if (n == ']' || n < c) {
  727.                 c = '-';
  728.                 break;    /* resume the for(;;) */
  729.             }
  730.             fmt++;
  731.             do {        /* fill in the range */
  732.                 tab[++c] = v;
  733.             } while (c < n);
  734. #if 1    /* XXX another disgusting compatibility hack */
  735.             /*
  736.              * Alas, the V7 Unix scanf also treats formats
  737.              * such as [a-c-e] as `the letters a through e'.
  738.              * This too is permitted by the standard....
  739.              */
  740.             goto doswitch;
  741. #else
  742.             c = *fmt++;
  743.             if (c == 0)
  744.                 return (fmt - 1);
  745.             if (c == ']')
  746.                 return (fmt);
  747. #endif
  748.             break;
  749.  
  750.         case ']':        /* end of scanset */
  751.             return (fmt);
  752.  
  753.         default:        /* just another character */
  754.             c = n;
  755.             break;
  756.         }
  757.     }
  758.     /* NOTREACHED */
  759. }
  760.